import { computed, onMounted, reactive, ref, watch } from 'vue';
export default function(props) {
  onMounted(() => {
    video.value = document.querySelector('video');
    if (state.mode === 'frame') {
      canvas.value = document.querySelector('#paintArea canvas');
      ctx.value = canvas.value.getContext('2d');
      methods.analysisVideo();
    }
  })
  const canvas = ref<any>({}); // 画布对象
  const ctx = ref<any>({}); // 画布对象
  const video = ref<any>(null); // 视频对象
  const animationId = ref(null);
  const state = reactive({
    // 播放状态
    isPlaying: false,
    // 等待状态
    waiting: false,
    // 总时长 对于video是 总秒数，对于frame是 总帧数
    duration: 0,
    // 目前播放时间
    currentTime: 0,
    // 静音
    muted: false,
    // 音量 0-100
    volume: 50,
    // 播放速度
    playbackRate: 1,
    fps: 25, // 播放帧率
    resource: {
      name: '',
      url: '',
      origin: {
        width: 0, // 原始宽度
        height: 0, // 原始高度
        scale: 0 // 放大缩小比例 显示高度 / 原始高度
      }
    },
    init: false,
    mode: 'frame' // video => 视频播放, frame => 帧播放
  })
  /** 进度条刻度尺 */
  const videoRuler = reactive({
    currentTime: 0,
    duration: 0,
    step: 5, // 每段长度
    stepArea: 12 // 多少段为一个大区间
  })
  /** 帧刻度尺 */
  const frameRuler = reactive({
    currentTime: 0,
    duration: 0,
    step: 0.04, // 每段长度
    stepArea: 25 // 多少段为一个大区间
  })
  const frameList = ref([]); // 右侧展示捕捉到的帧
  const allFrameList = ref([]) // 视频所有帧图片信息数据
  const loadedImages = ref([]) // 已经加载完的图片
  const allImagesLoaded = ref<boolean>(false);
  const frameControl = reactive<{
    rangeChoose: boolean;
    aroundOpen: boolean;
    captureFrameInterval: boolean;
  }>({
    rangeChoose: false, // 帧范围选择
    aroundOpen: false, // 周围帧开启
    captureFrameInterval: false // 定时捕获帧
  })
  const captureFrameInterval = ref(null); // 定时器 捕获帧
  /** 视频参数提示 */
  const videoTip = reactive({
    video: [
      {
        icon: 'el-icon-time',
        label: '总时长',
        text: '',
        bgColor: '#6fb2e5',
        color: '#0d67ab'
      },
      {
        icon: 'el-icon-video-camera',
        label: '分辨率',
        text: '',
        bgColor: '#d6b47d',
        color: '#d3870d'
      }
    ],
    frame: [
      {
        icon: 'el-icon-picture-outline',
        label: '总帧数',
        text: '',
        bgColor: '#bd7de5',
        color: '#8516cb'
      },
      {
        icon: 'el-icon-time',
        label: '总时长',
        text: '',
        bgColor: '#6fb2e5',
        color: '#0d67ab'
      },
      {
        icon: 'el-icon-video-camera',
        label: '分辨率',
        text: '',
        bgColor: '#d6b47d',
        color: '#d3870d'
      },
      {
        icon: 'el-icon-connection',
        label: 'FPS',
        text: '',
        bgColor: '#8ae5be',
        color: '#0b8e56'
      }
    ]
  })
  const videoName = computed(() => {
    return state.resource.name ?? '暂无视频'
  })
  const currentTime = computed(() => {
    return methods.timeFormat(state.currentTime)
  })
  const maxTime = computed(() => {
    return methods.timeFormat(state.duration)
  })
  const layout = ref('matrix') // list 列表 || matrix 矩阵
  const layoutList = reactive([
    {
      label: '矩阵',
      value: 'matrix'
    },
    {
      label: '列表',
      value: 'list'
    }
  ])
  const loading = reactive({
    text: '正在解析视频帧，请稍等',
    visible: false
  })
  const layoutStyle = computed(() => {
    const map = {
      list: {
        'display': 'grid',
        'grid-template-columns': '1fr',
        'gap': '16px'
      },
      matrix: {
        'display': 'grid',
        'grid-template-columns': 'repeat(3, 1fr)',
        'gap': '16px',
        'grid-template-rows': 'repeat(auto-fill, 100px)'
      }
    }
    return map[layout.value]
  })
  const aroundFrameList = computed(() => {
    if (!allFrameList.value.length) return []
    const result = [...methods.getNeighborsInclusive(allFrameList.value, state.currentTime, 3).prev, ...methods.getNeighborsInclusive(allFrameList.value, state.currentTime, 3).next]
    return result
  })
  /** 视频解析进度 */
  const percentageComputed = computed(() => {
    let percent = Number((allFrameList.value.length / (state.duration) * 100).toFixed(2));
    if (percent > 100) {
      percent = 100;
    }
    if (percent !== 100) {
      loading.visible = true;
    }
    return percent;
  })
  watch(() => props.video, val => {
    // 视频资源赋值
    state.resource.name = val.name;
    state.resource.url = val.url;
  }, {
    immediate: true
  })
  watch(() => props.mode, val => {
    state.mode = val;
  }, {
    immediate: true
  })
  const methods = {
    progressChange(e) {
      if (state.mode === 'video') {
        video.value.currentTime = state.currentTime = e;
      } else {
        state.currentTime = e;
      }
    },
    /**
     * 帧模式 播放结束
     */
    playend() {
      state.isPlaying = false;
      frameControl.captureFrameInterval = false;
    },
    /**
     * 获取周围帧
     * @param arr
     * @param index
     * @param n
     * @returns
     */
    getNeighborsInclusive(arr, index, n): null | {prev: [], next: []} {
      if (index < 0 || index >= arr.length) return null;
      return {
        prev: arr.slice(Math.max(0, index - n), index), // 前n个（不包含当前）
        next: arr.slice(index, Math.min(arr.length, index + n + 1)) // 后n个（包含当前）
      };
    },
    /**
     * 布局样式调整
     * @returns
     */
    calcLayout() {
      const scale = 0.6; // 按照左6右4比例来分配宽度
      const width = document.body.offsetWidth * scale;
      return {
        width
      }
    },
    /**
     * 视频参数提示初始化
     */
    videoTipInit() {
      if (state.mode === 'video') {
        videoTip[state.mode][0].text = state.duration + '秒';
        videoTip[state.mode][1].text = `${state.resource.origin.width}x${state.resource.origin.height}`;
      } else {
        videoTip[state.mode][0].text = state.duration + '帧';
        videoTip[state.mode][1].text = state.duration / state.fps + '秒';
        videoTip[state.mode][2].text = `${state.resource.origin.width}x${state.resource.origin.height}`;
        videoTip[state.mode][3].text = state.fps + 'FPS';
      }
    },
    /**
     * 刻度尺初始化
     */
    rulerInit() {
      state.init = true;
      let minStep = 5;
      if (state.mode === 'frame') {
        minStep *= state.fps;
      }
      videoRuler.duration = state.duration;
      const {
        step
      } = methods.findOptimalSteps(videoRuler.duration, minStep);
      videoRuler.step = step;
      videoRuler.stepArea = 1;
    },
    /**
     * 寻找指定数的因数
     * @param durationData
     * @param minStep
     * @returns
     */
    findOptimalSteps(durationData, minStep = 5) {
      const duration = durationData - durationData % 5;
      const result = { step: minStep };
      // 找出因数
      const possibleStepAreas = [];
      for (let i = 1; i <= Math.sqrt(duration); i++) {
        if (duration % i === 0) {
          possibleStepAreas.push(i);
          if (i !== duration / i) possibleStepAreas.push(duration / i);
        }
      }
      // 以453为例，possibleStepAreas数据为[1, 450, 2, 225, 3, 150, 5, 90, 6, 75, 9, 50, 10, 45, 15, 30, 18, 25]
      // 奇数位和偶数位互为因数，所以直接取两因数差值最短的值（奇数位）为step的值
      result.step = possibleStepAreas[possibleStepAreas.length - 2];
      return result;
    },
    /**
     * 元数据已加载完毕
     * @param res
     */
    onLoadedmetadata(res) {
      // 设置canvas dom宽高
      canvas.value.height = video.value.offsetHeight;
      canvas.value.width = (video.value.videoWidth * video.value.offsetHeight) / video.value.videoHeight;
      // 帧模式
      if (state.mode === 'frame') {
        video.value.style.opacity = 0;
        state.duration = parseInt(res.target.duration) * state.fps
        video.value.muted = true;
      // 视频模式
      } else {
        state.duration = parseInt(res.target.duration);
        video.value.muted = state.muted;
      }
      // 放大缩小比例
      state.resource.origin.scale = video.value.offsetHeight / video.value.videoHeight;
      state.waiting = false;
      video.value.volume = state.volume / 100;
      video.value.playbackRate = state.playbackRate;
      state.resource.origin.width = video.value.videoWidth;
      state.resource.origin.height = video.value.videoHeight;
      methods.rulerInit();
      methods.videoTipInit();
    },
    /**
     * 视频停止播放，因为媒体已经到达结束点
     */
    onEnded() {
      state.isPlaying = false;
      state.currentTime = video.value.currentTime = state.duration;
    },
    /**
     * 由 currentTime 属性指示的播放时间已更新
     */
    onTimeupdate() {
      videoRuler.currentTime = state.currentTime = video.value.currentTime;
    },
    onError(_err) {
      state.waiting = true;
    },
    /** 开始播放视频 */
    async start() {
      if (state.isPlaying) return;
      if (state.currentTime === state.duration) {
        state.currentTime = 0;
        video.value.currentTime = 0;
      }
      state.isPlaying = true;
      if (state.mode === 'video') {
        video.value.play();
      } else {
        methods.startAutoPlay();
        frameControl.aroundOpen = false;
      }
    },
    /** 暂停播放视频 */
    async pause() {
      if (!state.isPlaying) return;
      state.isPlaying = false;
      if (state.mode === 'video') {
        video.value.pause();
      } else {
        cancelAnimationFrame(animationId.value);
        animationId.value = null;
        frameControl.captureFrameInterval = false;
      }
    },
    /**
     * 预加载所有帧图片
     */
    preloadImages() {
      const loadPromises = allFrameList.value.map((src, index) => {
        return new Promise((resolve) => {
          const img = new Image();
          img.onload = () => {
            loadedImages.value[index] = img;
            resolve(true);
          };
          img.onerror = () => {
            console.error(`图片加载失败: ${src}`);
            // 可以在这里放置一个占位图片
            loadedImages.value[index] = methods.createPlaceholderImage();
            resolve(false);
          };
          img.src = src.url;
        });
      });
      Promise.all(loadPromises).then(() => {
        console.log('帧图片预加载完成, 正在绘制');
        allImagesLoaded.value = true;
        loading.visible = false;
        // 开始连续绘制 帧图片
        methods.start();
        // 示例 1s截图一次
      });
    },
    /**
     * 创建占位图片
     * @returns
     */
    createPlaceholderImage() {
      const img = new Image();
      const tmpCanvas = document.createElement('canvas');
      const ctx = tmpCanvas.getContext('2d');
      ctx.fillText('图片加载失败', canvas.width / 2, canvas.height / 2);
      img.src = tmpCanvas.toDataURL();
      return img;
    },
    /**
     * 绘制当前图片到Canvas
     * @returns
     */
    drawCurrentImage() {
      if (!allImagesLoaded.value || !loadedImages.value[state.currentTime]) return;
      ctx.value.clearRect(0, 0, canvas.value.width, canvas.value.height);
      const img = loadedImages.value[state.currentTime];
      const ratio = Math.min(
        canvas.value.width / img.width,
        canvas.value.height / img.height
      );
      const width = img.width * ratio;
      const height = img.height * ratio;
      const x = (canvas.value.width - width) / 2;
      const y = (canvas.value.height - height) / 2;
      ctx.value.drawImage(img, x, y, width, height);
    },
    /**
     * 图片展示控制逻辑
     * @param index 图片索引
     * @returns
     */
    showImage(index) {
      if (!allImagesLoaded.value || allFrameList.value.length === 0) return;
      if (index >= allFrameList.value.length) {
        state.currentTime = allFrameList.value.length - 1;
      } else if (index < 0) {
        state.currentTime = 0;
      } else {
        state.currentTime = index
      }
      videoRuler.currentTime = state.currentTime;
      methods.drawCurrentImage();
    },
    /**
     * 视频解析成帧图片
     */
    async analysisVideo() {
      const extractVideoFrames = async(videoUrl, frameInterval = 0.04) => {
        const video = document.createElement('video');
        video.muted = true;
        video.preload = 'auto'
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d', { willReadFrequently: true });
        let isTimeUpdated = false;
        video.addEventListener('timeupdate', () => (isTimeUpdated = true));
        // 加载视频
        const blob = await fetch(videoUrl).then(res => res.blob());
        // eslint-disable-next-line
        video.src = URL.createObjectURL(blob);
        // 等待视频准备就绪
        await new Promise(resolve => {
          video.addEventListener('loadedmetadata', resolve);
          video.addEventListener('canplaythrough', resolve);
        });
        // eslint-disable-next-line
        canvas.width = video.videoWidth;
        // eslint-disable-next-line
        canvas.height = video.videoHeight;
        // 提取帧
        const duration = video.duration;
        const frameTimes = [];
        for (let time = 0; time <= duration; time += frameInterval) {
          frameTimes.push(time);
        }
        const CONCURRENCY = 4; // 控制并发数
        for (let i = 0; i < frameTimes.length; i += CONCURRENCY) {
          const batch = frameTimes.slice(i, i + CONCURRENCY);
          await Promise.all(batch.map(async(seekTime) => {
            await new Promise(resolve => {
              isTimeUpdated = false;
              video.currentTime = seekTime;
              const checkFrame = () => {
                if (isTimeUpdated) {
                  context.clearRect(0, 0, canvas.width, canvas.height);
                  context.drawImage(video, 0, 0, canvas.width, canvas.height);
                  canvas.toBlob(blob => {
                    allFrameList.value.push({
                      time: seekTime,
                      url: URL.createObjectURL(blob)
                    });
                    resolve(true);
                  }, 'image/jpeg', 0.7);
                  return;
                }
                requestAnimationFrame(checkFrame);
              };
              checkFrame();
            });
          }));
        }
        // 按时间排序并返回URL
        return allFrameList.value.sort((a, b) => a.time - b.time).map((f, i) => {
          return {
            ...f,
            index: i
          }
        });
      };
      loading.visible = true;
      allFrameList.value = await extractVideoFrames(props.video.url, 0.04);
      methods.preloadImages();
    },
    /** 开始/暂停操作 */
    togglePlay() {
      if (state.isPlaying) {
        methods.pause();
      } else {
        methods.start();
      }
    },
    /**
     * 快退逻辑控制
     */
    prev() {
      if (state.mode === 'video') {
        methods.lastSecond();
      } else {
        methods.lastFrame();
      }
    },
    /**
     * 快进逻辑控制
     */
    next() {
      if (state.mode === 'video') {
        methods.nextSecond();
      } else {
        methods.nextFrame();
      }
    },
    /**
     * 快退
     * @param second 时间秒
     */
    lastSecond(second: number = 10) {
      state.currentTime -= second;
      if (state.currentTime <= state.duration) {
        video.value.currentTime = state.currentTime;
      } else {
        video.value.currentTime = state.duration;
        state.currentTime = state.duration;
      }
    },
    /**
     * 快进
     * @param second 时间秒
     */
    nextSecond(second: number = 10) {
      state.currentTime += second;
      if (state.currentTime >= 0) {
        video.value.currentTime = state.currentTime;
      } else {
        video.value.currentTime = 0;
        state.currentTime = 0;
      }
    },
    /**
     * 上一帧
     * @returns
     */
    async lastFrame() {
      methods.showImage(state.currentTime - 1);
    },
    /**
     * 下一帧
     * @returns
     */
    async nextFrame() {
      methods.showImage(state.currentTime + 1);
    },
    /**
     * 开始 帧模式播放
     */
    startAutoPlay() {
      let lastTime = 0;
      function frame(timestamp) {
        if (!state.isPlaying) return;
        const interval = 1000 / state.fps;
        if (timestamp - lastTime >= interval) {
          methods.showImage(state.currentTime + 1);
          lastTime = timestamp;
        }
        animationId.value = requestAnimationFrame(frame);
      }
      animationId.value = requestAnimationFrame(frame);
    },
    /**
     * 进度条toolTip
     * @param val
     * @returns
     */
    formatProcessToolTip(index) {
      const process = Math.ceil(index) + '%';
      return '播放进度: ' + process;
    },
    /**
     * 音量条toolTip
     * @param index
     * @returns
     */
    formatVolumeToolTip(index) {
      return '音量: ' + index + '%';
    },
    /**
     * 改变音量进度
     * @param index
     */
    changeVolume(index) {
      video.value.volume = index / 100;
      state.volume = index;
      video.value.muted = state.muted = !index;
    },
    /**
     * 改变视频进度
     * @param index
     */
    changeProgress(index) {
      state.currentTime = video.value.currentTime = Math.ceil(index / 100 * state.duration)
    },
    toggleVolume() {
      video.value.muted = !video.value.muted;
      state.muted = video.value.muted;
      if (video.value.muted) {
        video.value.volume = state.volume = 0;
      } else {
        state.volume = 50;
        video.value.volume = state.volume / 100
      }
    },
    timeFormat(second: any) {
      const secondType = typeof second;
      if (secondType === 'number' || secondType === 'string') {
        second = parseInt(second);
        const hours = Math.floor(second / 3600);
        second = second - hours * 3600;
        const minute = Math.floor(second / 60);
        second = second - minute * 60;
        return hours + ':' + ('0' + minute).slice(-2) + ':' + ('0' + second).slice(-2);
      } else {
        return '0:00:00';
      }
    },
    /**
     * 工具栏分发
     * @param tool 工具名
     * @param data 数据
     */
    operateHandler(tool, data) {
      if (!methods[tool]) return;
      methods[tool](data);
    },
    /**
     * 捕获帧
     */
    captureFrame() {
      // 周围帧打开时，则批量push帧
      if (frameControl.aroundOpen) {
        frameList.value.push(...aroundFrameList.value);
      // 否则只push当前时间下的帧
      } else {
        methods.singleCaptureFrame();
      }
    },
    /**
     * 单张捕获帧图片
     */
    singleCaptureFrame() {
      const imgData = allFrameList.value[state.currentTime];
      frameList.value.push(imgData);
    },
    /**
     * 定时捕获帧
     */
    captureFrameInterval() {
      if (!state.isPlaying) return;
      frameControl.captureFrameInterval = !frameControl.captureFrameInterval;
      if (frameControl.captureFrameInterval) {
        captureFrameInterval.value = setInterval(() => {
          if (!state.isPlaying) {
            clearInterval(captureFrameInterval.value);
            captureFrameInterval.value = null;
            return;
          }
          methods.singleCaptureFrame()
        }, 1000)
      } else {
        clearInterval(captureFrameInterval.value);
        captureFrameInterval.value = null;
      }
    },
    /**
     * 帧范围
     */
    rangeFrame() {
      frameControl.rangeChoose = !frameControl.rangeChoose;
    },
    /**
     * 周围帧
     */
    aroundFrame() {
      frameControl.aroundOpen = !frameControl.aroundOpen;
      // 打开周围帧时，若没有暂停播放，则主动去暂停
      if (frameControl.aroundOpen && state.isPlaying) {
        methods.pause();
      }
    },
    /**
     * 下载图片
     * @param image
     */
    downloadImage(image) {
      const a = document.createElement('a');
      a.href = image.url;
      a.download = `林大大哟视频剪辑工具${image.time}.jpg`; // 默认文件名
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    },
    /**
     * 删除图片
     * @param image
     */
    removeImage(image) {
      const deleteIndex = frameList.value.findIndex(item => item.time === image.time);
      if (deleteIndex !== -1) {
        frameList.value.splice(deleteIndex, 1)
      }
    },
    /**
     * 改变 捕获帧 布局样式
     * @param lay
     * @returns
     */
    changeLayout(lay) {
      if (!frameList.value.length) return;
      layout.value = lay.value
    }
  }

  return {
    methods,
    state,
    videoName,
    currentTime,
    maxTime,
    videoRuler,
    frameRuler,
    frameList,
    layoutStyle,
    layoutList,
    layout,
    aroundFrameList,
    frameControl,
    percentageComputed,
    loading,
    videoTip
  }
}
